#include "../lib_include/ThreadPool.h"
#include "../lib_include/Exception.h"

#include <assert.h>
#include <stdio.h>

using namespace netlib;

ThreadPool::ThreadPool(const string& nameArg)
    : mutex_(),
      notEmpty_(mutex_),
      notFull_(mutex_),
      name_(nameArg),
      maxQueueSize_(0),
      running_(false)
{ }

ThreadPool::~ThreadPool()
{
    if (running_)
        stop();
}

void ThreadPool::start(int numThreads) // 开启线程池
{
    assert(threads_.empty());
    running_ = true;
    threads_.reserve(numThreads);
    for (int i = 0; i < numThreads; ++i)
    {
        char id[32];
        snprintf(id, sizeof id, "%d", i+1);
        threads_.emplace_back(
            new netlib::Thread(std::bind(&ThreadPool::runInThread, this), name_+id)
        );
        threads_[i]->start();
    }
    if (numThreads == 0 && threadInitCallback_)
        threadInitCallback_();
}

void ThreadPool::stop() // 关闭线程池
{
    {
        MutexLockGuard lock(mutex_);
        running_ = false;
        notEmpty_.notifyAll();
        notFull_.notifyAll();
    }
    for (auto& thr : threads_)
        thr->join();
}

size_t ThreadPool::queueSize() const // 返回队列中元素个数
{
    MutexLockGuard lock(mutex_);
    return queue_.size();
}

void ThreadPool::run(Task task) // 插入任务
{
    if (threads_.empty()) // 如果线程池中没有线程，则直接运行任务函数
        task();
    else
    {
        MutexLockGuard lock(mutex_);
        while (isFull() && running_) // 如果队列已满，则等待空位
            notFull_.wait();
        if (!running_) return;
        assert(!isFull());

        queue_.push_back(std::move(task));
        notEmpty_.notify();
    }
}

ThreadPool::Task ThreadPool::take() // 从队列中取出任务
{
    MutexLockGuard lock(mutex_);
    while (queue_.empty() && running_)
        notEmpty_.wait();
        
    Task task;
    if (!queue_.empty())
    {
        task = queue_.front();
        queue_.pop_front();
        if (maxQueueSize_ > 0)
            notFull_.notify();
    }
    return task;
}

bool ThreadPool::isFull() const //判断是否已满
{
    mutex_.assertLocked();
    return maxQueueSize_ > 0 && queue_.size() >= maxQueueSize_;
}

void ThreadPool::runInThread() // 线程的入口函数
{
    try
    {
        if (threadInitCallback_)
            threadInitCallback_();
        while (running_)
        {
            Task task(take());
            if (task)
                task();
        }
    }
    catch (const Exception& ex)
    {
        fprintf(stderr, "exception caught in ThreadPool %s\n", name_.c_str());
        fprintf(stderr, "reason: %s\n", ex.what());
        fprintf(stderr, "stack trace: %s\n", ex.stackTrace());
        abort();
    }
    catch (const std::exception& ex)
    {
        fprintf(stderr, "exception caught in ThreadPool %s\n", name_.c_str());
        fprintf(stderr, "reason: %s\n", ex.what());
        abort();
    }
    catch (...)
    {
        fprintf(stderr, "unknown exception caught in ThreadPool %s\n", name_.c_str());
        throw; // rethrow
    }
}

